home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 1 / Cream of the Crop 1.iso / PROGRAM / GIFLIB12.ARJ / GIF2X11.C < prev    next >
C/C++ Source or Header  |  1991-05-12  |  18KB  |  518 lines

  1. /*****************************************************************************
  2. *   "Gif-Lib" - Yet another gif library.                     *
  3. *                                         *
  4. * Written by:  Gershon Elber                Ver 0.1, Jul. 1989   *
  5. ******************************************************************************
  6. * Program to display GIF file under X11 window system.                 *
  7. * Options:                                     *
  8. * -q : quite printing mode.                             *
  9. * -p PosX PosY : defines the position where to put the image.             *
  10. * -d Display : what display should go to.                     *
  11. * -f : force attempt to allocate the exact colors. This usually look bad...  *
  12. * -h : on line help.                                 *
  13. ******************************************************************************
  14. * History:                                     *
  15. * 28 Dec 89 - Version 1.0 by Gershon Elber, color allocation is based on the *
  16. *        xgif program by John Bradley, bradley@cis.ipenn.edu.         *
  17. *****************************************************************************/
  18.  
  19. #ifdef __MSDOS__
  20. #include <graphics.h>
  21. #include <stdlib.h>
  22. #include <alloc.h>
  23. #include <io.h>
  24. #include <dos.h>
  25. #include <bios.h>
  26. #endif /* __MSDOS__ */
  27.  
  28. #include <X11/Xlib.h>
  29. #include <X11/Xutil.h>
  30. #include <X11/cursorfont.h>
  31.  
  32. #include <stdio.h>
  33. #include <ctype.h>
  34. #include <string.h>
  35. #include <fcntl.h>
  36. #include "gif_lib.h"
  37. #include "getarg.h"
  38.  
  39. #define PROGRAM_NAME    "Gif2X11"
  40.  
  41. #define ICON_SIZE    60
  42. #define ABS(x)        ((x) > 0 ? (x) : (-(x)))
  43.  
  44. #ifdef __MSDOS__
  45. extern unsigned int
  46.     _stklen = 16384;                 /* Increase default stack size. */
  47. #endif /* __MSDOS__ */
  48. #ifdef SYSV
  49. static char *VersionStr =
  50.         "Gif library module,\t\tGershon Elber\n\
  51.     (C) Copyright 1989 Gershon Elber, Non commercial use only.\n";
  52. static char
  53.     *CtrlStr = "Gif2X11 q%- p%-PosX|PosY!d!d d%-Display!s f%- h%- GifFile!*s";
  54. #else
  55. static char
  56.     *VersionStr =
  57.     PROGRAM_NAME
  58.     GIF_LIB_VERSION
  59.     "    Gershon Elber,    "
  60.     __DATE__ ",   " __TIME__ "\n"
  61.     "(C) Copyright 1989 Gershon Elber, Non commercial use only.\n";
  62. static char
  63.     *CtrlStr =
  64.     PROGRAM_NAME
  65.     " q%- p%-PosX|PosY!d!d d%-Display!s f%- h%- GifFile!*s";
  66. #endif /* SYSV */
  67.  
  68. /* Make some variables global, so we could access them faster: */
  69. static int
  70.     PosFlag = FALSE,
  71.     HelpFlag = FALSE,
  72.     DisplayFlag = FALSE,
  73.     ForceFlag = FALSE,
  74.     ColorMapSize = 0,
  75.     BackGround = 0,
  76.     XPosX = 0,
  77.     XPosY = 0,
  78.     InterlacedOffset[] = { 0, 4, 2, 1 }, /* The way Interlaced image should. */
  79.     InterlacedJumps[] = { 8, 8, 4, 2 };    /* be read - offsets and jumps... */
  80. static char
  81.     *DisplayName = NULL;
  82. static GifColorType
  83.     *ColorMap;
  84.  
  85. /* X specific staff goes here. XColorTable will hold the GIF image colors,   */
  86. /* while XPixelTable will hold the pixel number so we can redirect through   */
  87. /* it when forming the image bitmap in X format.                 */
  88. /* Note the table has 256 entry which is the maximum allowed in GIF format.  */
  89. static XColor XColorTable[256];
  90. static unsigned long XPixelTable[256];
  91. static Display *XDisplay;
  92. static int XScreen;
  93. static Window Xroot, XImageWndw;
  94. static Colormap XColorMap;
  95. static GC XGraphContext;
  96. static Visual *XVisual;
  97. static XImage *XImageBuffer;
  98. static Pixmap XIcon;
  99. static Cursor XCursor;
  100.  
  101. static void Screen2X(int argc, char **argv, GifRowType *ScreenBuffer,
  102.              int ScreenWidth, int ScreenHeight);
  103. static void AllocateColors1(void);
  104. static void AllocateColors2(void);
  105.  
  106. /******************************************************************************
  107. * Interpret the command line and scan the given GIF file.              *
  108. ******************************************************************************/
  109. void main(int argc, char **argv)
  110. {
  111.     int    i, j, Error, NumFiles, ImageNum = 0, Size, Row, Col, Width, Height,
  112.         ExtCode, Count;
  113.     GifRecordType RecordType;
  114.     GifByteType *Extension;
  115.     char **FileName = NULL;
  116.     GifRowType *ScreenBuffer;
  117.     GifFileType *GifFile;
  118.  
  119.     if ((Error = GAGetArgs(argc, argv, CtrlStr,
  120.         &GifQuitePrint, &PosFlag, &XPosX, &XPosY,
  121.             &DisplayFlag, &DisplayName, &ForceFlag,
  122.         &HelpFlag, &NumFiles, &FileName)) != FALSE ||
  123.         (NumFiles > 1 && !HelpFlag)) {
  124.     if (Error)
  125.         GAPrintErrMsg(Error);
  126.     else if (NumFiles > 1)
  127.         GIF_MESSAGE("Error in command line parsing - one GIF file please.");
  128.     GAPrintHowTo(CtrlStr);
  129.     exit(1);
  130.     }
  131.  
  132.     if (HelpFlag) {
  133.     fprintf(stderr, VersionStr);
  134.     GAPrintHowTo(CtrlStr);
  135.     exit(0);
  136.     }
  137.  
  138.     if (NumFiles == 1) {
  139.     if ((GifFile = DGifOpenFileName(*FileName)) == NULL) {
  140.         PrintGifError();
  141.         exit(-1);
  142.     }
  143.     }
  144.     else {
  145.     /* Use the stdin instead: */
  146.  
  147. #ifdef __MSDOS__
  148.     setmode(0, O_BINARY);
  149. #endif /* __MSDOS__ */
  150.     if ((GifFile = DGifOpenFileHandle(0)) == NULL) {
  151.         PrintGifError();
  152.         exit(-1);
  153.     }
  154.     }
  155.  
  156.     /* Lets see if we can get access to the X server before we even start: */
  157.     if ((XDisplay = (Display *) XOpenDisplay(DisplayName)) == NULL)
  158.     GIF_EXIT("Failed to access X server, abored.");
  159.     XScreen = DefaultScreen(XDisplay);
  160.     Xroot = RootWindow(XDisplay, XScreen);
  161.     XColorMap = DefaultColormap(XDisplay, XScreen);
  162.     XGraphContext = DefaultGC(XDisplay, XScreen);
  163.     XVisual = DefaultVisual(XDisplay, XScreen);
  164.     XSetBackground(XDisplay, XGraphContext, BlackPixel(XDisplay, XScreen));
  165.     XSetForeground(XDisplay, XGraphContext, WhitePixel(XDisplay, XScreen));
  166.  
  167.     /* Allocate the screen as vector of column of rows. We cannt allocate    */
  168.     /* the all screen at once, as this broken minded CPU can allocate up to  */
  169.     /* 64k at a time and our image can be bigger than that:             */
  170.     /* Note this screen is device independent - its the screen as defined by */
  171.     /* the GIF file parameters itself.                         */
  172.     if ((ScreenBuffer = (GifRowType *)
  173.     malloc(GifFile -> SHeight * sizeof(GifRowType *))) == NULL)
  174.         GIF_EXIT("Failed to allocate memory required, aborted.");
  175.  
  176.     Size = GifFile -> SWidth * sizeof(GifPixelType);/* Size in bytes one row.*/
  177.     if ((ScreenBuffer[0] = (GifRowType) malloc(Size)) == NULL) /* First row. */
  178.     GIF_EXIT("Failed to allocate memory required, aborted.");
  179.  
  180.     for (i = 0; i < GifFile -> SWidth; i++)  /* Set its color to BackGround. */
  181.     ScreenBuffer[0][i] = GifFile -> SBackGroundColor;
  182.     for (i = 1; i < GifFile -> SHeight; i++) {
  183.     /* Allocate the other rows, and set their color to background too: */
  184.     if ((ScreenBuffer[i] = (GifRowType) malloc(Size)) == NULL)
  185.         GIF_EXIT("Failed to allocate memory required, aborted.");
  186.  
  187.     memcpy(ScreenBuffer[i], ScreenBuffer[0], Size);
  188.     }
  189.  
  190.     /* Scan the content of the GIF file and load the image(s) in: */
  191.     do {
  192.     if (DGifGetRecordType(GifFile, &RecordType) == GIF_ERROR) {
  193.         PrintGifError();
  194.         exit(-1);
  195.     }
  196.     switch (RecordType) {
  197.         case IMAGE_DESC_RECORD_TYPE:
  198.         if (DGifGetImageDesc(GifFile) == GIF_ERROR) {
  199.             PrintGifError();
  200.             exit(-1);
  201.         }
  202.         Row = GifFile -> ITop; /* Image Position relative to Screen. */
  203.         Col = GifFile -> ILeft;
  204.         Width = GifFile -> IWidth;
  205.         Height = GifFile -> IHeight;
  206.         GifQprintf("\n%s: Image %d at (%d, %d) [%dx%d]:     ",
  207.             PROGRAM_NAME, ++ImageNum, Col, Row, Width, Height);
  208.         if (GifFile -> ILeft + GifFile -> IWidth > GifFile -> SWidth ||
  209.            GifFile -> ITop + GifFile -> IHeight > GifFile -> SHeight) {
  210.             fprintf(stderr, "Image %d is not confined to screen dimension, aborted.\n");
  211.             exit(-2);
  212.         }
  213.         if (GifFile -> IInterlace) {
  214.             /* Need to perform 4 passes on the images: */
  215.             for (Count = i = 0; i < 4; i++)
  216.             for (j = Row + InterlacedOffset[i]; j<Row + Height;
  217.                          j += InterlacedJumps[i]) {
  218.                 GifQprintf("\b\b\b\b%-4d", Count++);
  219.                 if (DGifGetLine(GifFile, &ScreenBuffer[j][Col],
  220.                 Width) == GIF_ERROR) {
  221.                 PrintGifError();
  222.                 exit(-1);
  223.                 }
  224.             }
  225.         }
  226.         else {
  227.             for (i = 0; i < Height; i++) {
  228.             GifQprintf("\b\b\b\b%-4d", i);
  229.             if (DGifGetLine(GifFile, &ScreenBuffer[Row++][Col],
  230.                 Width) == GIF_ERROR) {
  231.                 PrintGifError();
  232.                 exit(-1);
  233.             }
  234.             }
  235.         }
  236.         break;
  237.         case EXTENSION_RECORD_TYPE:
  238.         /* Skip any extension blocks in file: */
  239.         if (DGifGetExtension(GifFile, &ExtCode, &Extension) == GIF_ERROR) {
  240.             PrintGifError();
  241.             exit(-1);
  242.         }
  243.         while (Extension != NULL) {
  244.             if (DGifGetExtensionNext(GifFile, &Extension) == GIF_ERROR) {
  245.             PrintGifError();
  246.             exit(-1);
  247.             }
  248.         }
  249.         break;
  250.         case TERMINATE_RECORD_TYPE:
  251.         break;
  252.         default:            /* Should be traps by DGifGetRecordType. */
  253.         break;
  254.     }
  255.     }
  256.     while (RecordType != TERMINATE_RECORD_TYPE);
  257.  
  258.     /* Lets display it - set the global variables required and do it: */
  259.     BackGround = GifFile -> SBackGroundColor;
  260.     ColorMap = (GifFile -> IColorMap ? GifFile -> IColorMap :
  261.                        GifFile -> SColorMap);
  262.     ColorMapSize = 1 << (GifFile -> IColorMap ? GifFile -> IBitsPerPixel :
  263.                                 GifFile -> SBitsPerPixel);
  264.     Screen2X(argc, argv, ScreenBuffer, GifFile -> SWidth, GifFile -> SHeight);
  265.  
  266.     if (DGifCloseFile(GifFile) == GIF_ERROR) {
  267.     PrintGifError();
  268.     exit(-1);
  269.     }
  270.     GifQprintf("\n");
  271. }
  272.  
  273. /******************************************************************************
  274. * The real display routine.                              *
  275. ******************************************************************************/
  276. static void Screen2X(int argc, char **argv, GifRowType *ScreenBuffer,
  277.              int ScreenWidth, int ScreenHeight)
  278. {
  279.     int i, j, c, Size, x, y,
  280.         MinIntensity, MaxIntensity, AvgIntensity, IconSizeX, IconSizeY;
  281.     char *XImageData, *XIconData, KeyBuffer[81];
  282.     double Aspect;
  283.     GifByteType *OutLine, Data;
  284.     unsigned long ValueMask;
  285.     GifPixelType *Line;
  286.     GifRowType *DitherBuffer;
  287.     GifColorType *ColorMapEntry = ColorMap;
  288.     XSetWindowAttributes SetWinAttr;
  289.     XSizeHints Hints;
  290.     XEvent Event;
  291.     XExposeEvent *EEvent;
  292.     XComposeStatus Stat;
  293.     KeySym KS;
  294.  
  295.     /* Let find out what are the intensities in the color map: */
  296.     MaxIntensity = 0;
  297.     MinIntensity = 256 * 100;
  298.     for (i = 0; i < ColorMapSize; i++) {
  299.     c = ColorMapEntry[i].Red * 30 +
  300.         ColorMapEntry[i].Green * 59 +
  301.         ColorMapEntry[i].Blue * 11;
  302.     if (c > MaxIntensity) MaxIntensity = c;
  303.     if (c < MinIntensity) MinIntensity = c;
  304.     }
  305.     AvgIntensity = (MinIntensity + MaxIntensity) / 2;
  306.  
  307.     /* The big trick here is to select the colors so lets do this first: */
  308.     if (ForceFlag)
  309.     AllocateColors2();
  310.     else
  311.     AllocateColors1();
  312.  
  313.     SetWinAttr.background_pixel = BlackPixel( XDisplay, XScreen );
  314.     SetWinAttr.border_pixel = WhitePixel( XDisplay, XScreen );
  315.     ValueMask = CWBackPixel | CWBorderPixel;
  316.  
  317.     Hints.flags = PSize | PMinSize | PMaxSize;
  318.     Hints.x = Hints.y = 1;
  319.     Hints.width = Hints.min_width = Hints.max_width = ScreenWidth;
  320.     Hints.height = Hints.min_height = Hints.max_height = ScreenHeight;
  321.     if (PosFlag) {
  322.     Hints.flags |= USPosition;
  323.     Hints.x = XPosX;
  324.     Hints.y = XPosY;
  325.     }
  326.  
  327.     XImageWndw = XCreateWindow(XDisplay, Xroot, XPosX, XPosY,
  328.                    ScreenWidth, ScreenHeight,
  329.                    1, 0,
  330.                    CopyFromParent, CopyFromParent,
  331.                    ValueMask, &SetWinAttr);
  332.  
  333.     /* Set up the icon bit map to be a shrinked BW version of the image: */
  334.     if (ScreenWidth > ScreenHeight) {
  335.     IconSizeX = (ICON_SIZE / 8) * 8;
  336.     IconSizeY = (ScreenHeight * ICON_SIZE) / ScreenWidth;
  337.     }
  338.     else {
  339.     IconSizeY = ICON_SIZE;
  340.     IconSizeX = (((ScreenWidth * ICON_SIZE) / ScreenHeight) / 8) * 8;
  341.     }
  342.     XIconData = (char *) malloc(IconSizeX * IconSizeY / 8);
  343.     memset(XIconData, 0, IconSizeX * IconSizeY / 8);
  344.     for (i = 0; i < IconSizeY; i++) {
  345.     y = (i * ScreenHeight / IconSizeY);
  346.     Size = i * IconSizeX / 8;
  347.     for (j = 0; j < IconSizeX; j++) {
  348.         x = j * ScreenWidth / IconSizeX;
  349.         c = ScreenBuffer[y][x];
  350.         c = ColorMapEntry[c].Red * 30 +
  351.         ColorMapEntry[c].Green * 59 +
  352.         ColorMapEntry[c].Blue * 11 > AvgIntensity;
  353.         XIconData[Size + j / 8] |= c << (j % 8);
  354.     }
  355.     }
  356.  
  357.     XIcon = XCreateBitmapFromData(XDisplay, XImageWndw, XIconData,
  358.                   IconSizeX, IconSizeY);
  359.  
  360.     XSetStandardProperties(XDisplay, XImageWndw,
  361.                PROGRAM_NAME, PROGRAM_NAME, XIcon,
  362.                argv, argc,
  363.                &Hints);
  364.  
  365.     XSelectInput(XDisplay, XImageWndw, ExposureMask | KeyPressMask);
  366.  
  367.     /* Set out own cursor: */
  368.     XCursor = XCreateFontCursor(XDisplay, XC_diamond_cross);
  369.     XDefineCursor(XDisplay, XImageWndw, XCursor);
  370.     
  371.     XMapWindow(XDisplay, XImageWndw);
  372.  
  373.     /* Create the image in X format: */
  374.     if ((XImageData = (char *) malloc(ScreenWidth * ScreenHeight)) == NULL)
  375.     GIF_EXIT("Failed to allocate memory required, aborted.");
  376.  
  377.     for (i = 0; i < ScreenHeight; i++) {
  378.     y = i * ScreenWidth;
  379.     for (j = 0; j < ScreenWidth; j++)
  380.         XImageData[y + j] = XPixelTable[ScreenBuffer[i][j]];
  381.     }
  382.     XImageBuffer = XCreateImage(XDisplay, XVisual, 8, ZPixmap, 0,
  383.                 XImageData, ScreenWidth, ScreenHeight,
  384.                 8, ScreenWidth);
  385.  
  386.     while (TRUE) {
  387.     XNextEvent(XDisplay, &Event);
  388.     switch (Event.type) {
  389.         case Expose:
  390.             EEvent = (XExposeEvent *) &Event;
  391.         XPutImage(XDisplay, XImageWndw, XGraphContext, XImageBuffer,
  392.               EEvent -> x, EEvent -> y,
  393.               EEvent -> x, EEvent -> y,
  394.               EEvent -> width, EEvent -> height);
  395.         break;
  396.         case KeyPress:
  397.         XLookupString(&Event, KeyBuffer, 80, &KS, &Stat);
  398.         if (KeyBuffer[0] == 3) return;
  399.         break;
  400.     }
  401.     }
  402. }
  403.  
  404. /******************************************************************************
  405. * Routine to allocate the requested colors from the X server.              *
  406. * Colors are allocated until success by stripping off the least bits of the   *
  407. * colors.                                      *
  408. ******************************************************************************/
  409. static void AllocateColors1(void)
  410. {
  411.     int Strip, Msk, i, j;
  412.     char Msg[80];
  413.  
  414.     for (i = 0; i < 256; i++)
  415.     XPixelTable[i] = 0;       /* Put reasonable color for out of range. */
  416.  
  417.     for (Strip = 0, Msk = 0xff; Strip < 8; Strip++, Msk <<= 1) {
  418.     for (i = 0; i < ColorMapSize; i++) {
  419.         /* Prepere color entry in X format. */
  420.         XColorTable[i].red = (ColorMap[i].Red & Msk) << 8;
  421.         XColorTable[i].green = (ColorMap[i].Green & Msk) << 8;
  422.         XColorTable[i].blue = (ColorMap[i].Blue & Msk) << 8;
  423.         XColorTable[i].flags = DoRed | DoGreen | DoBlue;
  424.         if (XAllocColor(XDisplay, XColorMap, &XColorTable[i]))
  425.         XPixelTable[i] = XColorTable[i].pixel;
  426.         else
  427.         break;
  428.     }
  429.     if (i < ColorMapSize)
  430.         XFreeColors(XDisplay, XColorMap, XPixelTable, i, 0L);
  431.     else
  432.         break;
  433.     }
  434.  
  435.     if (Strip == 8)
  436.     GIF_EXIT("Can not display the image - not enough colors available.");
  437.  
  438.     if (Strip != 0) {
  439.     sprintf(Msg, "%d bits were stripped off the color map.", Strip);
  440.     GIF_MESSAGE(Msg);
  441.     }
  442. }
  443.  
  444. /******************************************************************************
  445. * Routine to allocate the requested colors from the X server.              *
  446. * Two stages are performed:                              *
  447. * 1. Colors are requested directly.                          *
  448. * 2. If not enough colors can be allocated, the closest current color          *
  449. *    in current table is selected instead.                      *
  450. * This allocation is not optimal as when fail to allocate all colors one      *
  451. * should pick the right colors to do allocate in order to minimize the        *
  452. * closest distance from the unallocated ones under some norm (what is a good  *
  453. * norm for the RGB space?). Improve it if you are bored.              *
  454. ******************************************************************************/
  455. static void AllocateColors2(void)
  456. {
  457.     int i, j, Index = 0, Count = 0, XNumOfColors;
  458.     char Msg[80];
  459.     unsigned long D, Distance, AvgDistance = 0, Red, Green, Blue;
  460.     GifBooleanType Failed = FALSE;
  461.     XColor *XOldColorTable;
  462.  
  463.     for (i = 0; i < 256; i++) {
  464.     if (i < ColorMapSize) {          /* Prepere color entry in X format. */
  465.         XColorTable[i].red = ColorMap[i].Red << 8;
  466.         XColorTable[i].green = ColorMap[i].Green << 8;
  467.         XColorTable[i].blue = ColorMap[i].Blue << 8;
  468.         XColorTable[i].flags = DoRed | DoGreen | DoBlue;
  469.         XPixelTable[i] = -1;               /* Not allocated yet. */
  470.     }
  471.     else
  472.         XPixelTable[i] = 0;    /* Put reasonable color for out of range. */
  473.     }
  474.  
  475.     for (i = 0; i < ColorMapSize; i++)          /* Allocate the colors from X: */
  476.     if (XAllocColor(XDisplay, XColorMap, &XColorTable[i]))
  477.         XPixelTable[i] = XColorTable[i].pixel;
  478.     else
  479.         Failed = TRUE;
  480.  
  481.     if (Failed) {
  482.     XNumOfColors = DisplayCells(XDisplay, XScreen);
  483.     XOldColorTable = (XColor *) malloc(sizeof(XColor) * XNumOfColors);
  484.     for (i = 0; i < XNumOfColors; i++) XOldColorTable[i].pixel = i;
  485.     XQueryColors(XDisplay, XColorMap, XOldColorTable, XNumOfColors);
  486.     
  487.     for (i = 0; i < ColorMapSize; i++) {
  488.         /* Allocate closest colors from X: */
  489.         if (XPixelTable[i] == -1) {      /* Failed to allocate this one. */
  490.         Distance = 0xffffffff;
  491.  
  492.         Red = XColorTable[i].red;
  493.         Green = XColorTable[i].green;
  494.         Blue = XColorTable[i].blue;
  495.  
  496.         for (j = 0; j < XNumOfColors; j++) {
  497.             /* Find the closest color in 3D RGB space using L1 norm. */
  498.             if ((D = ABS(Red - XOldColorTable[j].red) +
  499.                  ABS(Green - XOldColorTable[j].green) +
  500.                  ABS(Blue - XOldColorTable[j].blue)) < Distance) {
  501.             Distance = D;
  502.             Index = j;
  503.             }
  504.         }
  505.             XPixelTable[i] = Index;
  506.  
  507.         AvgDistance += Distance;
  508.         Count++;
  509.         }
  510.     }
  511.     free(XOldColorTable);
  512.  
  513.     sprintf(Msg, "Colors will be approximated (average error = %d).\n",
  514.         AvgDistance / Count);
  515.     GIF_MESSAGE(Msg);
  516.     }
  517. }
  518.